#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
练习题21: Python魔术方法深度实践

本练习涵盖Python中最重要的魔术方法(Magic Methods/Dunder Methods)，
包括对象表示、比较操作、算术运算、容器协议等。

知识点:
- 对象表示: __str__, __repr__, __format__
- 比较操作: __eq__, __ne__, __lt__, __le__, __gt__, __ge__
- 哈希支持: __hash__, __bool__
- 算术运算: __add__, __sub__, __mul__, __truediv__
- 容器协议: __len__, __getitem__, __setitem__, __delitem__
- 可调用对象: __call__
- 属性访问: __getattr__, __setattr__, __delattr__
- 上下文管理: __enter__, __exit__
"""

import functools
from typing import Any, Iterator, Optional, Union
from collections.abc import MutableMapping


class SmartNumber:
    """
    练习1: 实现一个智能数字类，支持各种魔术方法
    
    要求:
    1. 支持基本算术运算(+, -, *, /)
    2. 支持比较操作(==, !=, <, <=, >, >=)
    3. 支持哈希和布尔转换
    4. 提供清晰的字符串表示
    5. 支持格式化输出
    """
    
    def __init__(self, value: Union[int, float]):
        if not isinstance(value, (int, float)):
            raise TypeError(f"Expected int or float, got {type(value).__name__}")
        self._value = value
    
    def __str__(self) -> str:
        """用户友好的字符串表示"""
        # TODO: 实现用户友好的字符串表示
        # 提示: 返回简洁的数值表示
        pass
    
    def __repr__(self) -> str:
        """开发者友好的字符串表示"""
        # TODO: 实现开发者友好的字符串表示
        # 提示: 返回可以重新创建对象的表示
        pass
    
    def __format__(self, format_spec: str) -> str:
        """格式化输出支持"""
        # TODO: 实现格式化输出
        # 提示: 支持常见的数字格式化选项
        pass
    
    def __eq__(self, other) -> bool:
        """相等比较"""
        # TODO: 实现相等比较
        # 提示: 考虑类型检查和数值比较
        pass
    
    def __ne__(self, other) -> bool:
        """不等比较"""
        # TODO: 实现不等比较
        # 提示: 可以基于__eq__实现
        pass
    
    def __lt__(self, other) -> bool:
        """小于比较"""
        # TODO: 实现小于比较
        pass
    
    def __le__(self, other) -> bool:
        """小于等于比较"""
        # TODO: 实现小于等于比较
        pass
    
    def __gt__(self, other) -> bool:
        """大于比较"""
        # TODO: 实现大于比较
        pass
    
    def __ge__(self, other) -> bool:
        """大于等于比较"""
        # TODO: 实现大于等于比较
        pass
    
    def __hash__(self) -> int:
        """哈希支持"""
        # TODO: 实现哈希方法
        # 提示: 确保相等的对象有相同的哈希值
        pass
    
    def __bool__(self) -> bool:
        """布尔转换"""
        # TODO: 实现布尔转换
        # 提示: 0应该为False，其他为True
        pass
    
    def __add__(self, other):
        """加法运算"""
        # TODO: 实现加法运算
        # 提示: 支持与数字和同类型对象相加
        pass
    
    def __radd__(self, other):
        """反向加法运算"""
        # TODO: 实现反向加法运算
        pass
    
    def __sub__(self, other):
        """减法运算"""
        # TODO: 实现减法运算
        pass
    
    def __rsub__(self, other):
        """反向减法运算"""
        # TODO: 实现反向减法运算
        pass
    
    def __mul__(self, other):
        """乘法运算"""
        # TODO: 实现乘法运算
        pass
    
    def __rmul__(self, other):
        """反向乘法运算"""
        # TODO: 实现反向乘法运算
        pass
    
    def __truediv__(self, other):
        """除法运算"""
        # TODO: 实现除法运算
        # 提示: 注意除零错误
        pass
    
    def __rtruediv__(self, other):
        """反向除法运算"""
        # TODO: 实现反向除法运算
        pass
    
    @property
    def value(self) -> Union[int, float]:
        """获取数值"""
        return self._value


class SmartList:
    """
    练习2: 实现一个智能列表类，支持容器协议
    
    要求:
    1. 支持索引访问和切片操作
    2. 支持长度获取和成员检测
    3. 支持迭代和反向迭代
    4. 支持列表修改操作
    5. 提供清晰的字符串表示
    """
    
    def __init__(self, items=None):
        self._items = list(items) if items else []
    
    def __str__(self) -> str:
        """字符串表示"""
        # TODO: 实现字符串表示
        pass
    
    def __repr__(self) -> str:
        """开发者表示"""
        # TODO: 实现开发者表示
        pass
    
    def __len__(self) -> int:
        """长度获取"""
        # TODO: 实现长度获取
        pass
    
    def __getitem__(self, key):
        """索引访问"""
        # TODO: 实现索引访问和切片支持
        # 提示: 支持负索引和切片操作
        pass
    
    def __setitem__(self, key, value):
        """索引设置"""
        # TODO: 实现索引设置
        pass
    
    def __delitem__(self, key):
        """索引删除"""
        # TODO: 实现索引删除
        pass
    
    def __contains__(self, item) -> bool:
        """成员检测"""
        # TODO: 实现成员检测
        pass
    
    def __iter__(self) -> Iterator:
        """迭代支持"""
        # TODO: 实现迭代支持
        pass
    
    def __reversed__(self) -> Iterator:
        """反向迭代"""
        # TODO: 实现反向迭代
        pass
    
    def __eq__(self, other) -> bool:
        """相等比较"""
        # TODO: 实现相等比较
        pass
    
    def __add__(self, other):
        """列表连接"""
        # TODO: 实现列表连接
        pass
    
    def __iadd__(self, other):
        """就地连接"""
        # TODO: 实现就地连接
        pass
    
    def append(self, item):
        """添加元素"""
        self._items.append(item)
    
    def extend(self, items):
        """扩展列表"""
        self._items.extend(items)


class CallableClass:
    """
    练习3: 实现一个可调用的类
    
    要求:
    1. 实现__call__方法使对象可调用
    2. 支持不同的调用模式
    3. 记录调用历史
    4. 支持装饰器模式
    """
    
    def __init__(self, func=None):
        self._func = func
        self._call_count = 0
        self._call_history = []
    
    def __call__(self, *args, **kwargs):
        """使对象可调用"""
        # TODO: 实现可调用功能
        # 提示: 记录调用次数和历史，执行函数
        pass
    
    def __str__(self) -> str:
        # TODO: 实现字符串表示
        pass
    
    @property
    def call_count(self) -> int:
        """获取调用次数"""
        return self._call_count
    
    @property
    def call_history(self) -> list:
        """获取调用历史"""
        return self._call_history.copy()


class AttributeProxy:
    """
    练习4: 实现一个属性代理类
    
    要求:
    1. 实现动态属性访问
    2. 支持属性设置和删除
    3. 提供属性访问日志
    4. 支持属性验证
    """
    
    def __init__(self, target=None):
        # 使用object.__setattr__避免递归
        object.__setattr__(self, '_target', target or {})
        object.__setattr__(self, '_access_log', [])
    
    def __getattr__(self, name: str) -> Any:
        """动态属性获取"""
        # TODO: 实现动态属性获取
        # 提示: 记录访问日志，从目标对象获取属性
        pass
    
    def __setattr__(self, name: str, value: Any) -> None:
        """属性设置"""
        # TODO: 实现属性设置
        # 提示: 避免设置内部属性时的递归
        pass
    
    def __delattr__(self, name: str) -> None:
        """属性删除"""
        # TODO: 实现属性删除
        pass
    
    def __dir__(self):
        """属性列表"""
        # TODO: 实现属性列表
        pass
    
    @property
    def access_log(self) -> list:
        """获取访问日志"""
        return self._access_log.copy()


class ContextManager:
    """
    练习5: 实现一个上下文管理器
    
    要求:
    1. 实现__enter__和__exit__方法
    2. 支持异常处理
    3. 提供资源管理功能
    4. 支持嵌套使用
    """
    
    def __init__(self, resource_name: str):
        self.resource_name = resource_name
        self.is_acquired = False
        self.enter_count = 0
    
    def __enter__(self):
        """进入上下文"""
        # TODO: 实现上下文进入
        # 提示: 获取资源，记录状态
        pass
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文"""
        # TODO: 实现上下文退出
        # 提示: 释放资源，处理异常
        pass
    
    def __str__(self) -> str:
        return f"ContextManager({self.resource_name})"


class SmartDict(MutableMapping):
    """
    练习6: 实现一个智能字典类
    
    要求:
    1. 继承MutableMapping抽象基类
    2. 实现所有必需的抽象方法
    3. 支持点号访问属性
    4. 提供类型安全的访问
    """
    
    def __init__(self, *args, **kwargs):
        self._data = dict(*args, **kwargs)
    
    def __getitem__(self, key):
        """字典访问"""
        # TODO: 实现字典访问
        pass
    
    def __setitem__(self, key, value):
        """字典设置"""
        # TODO: 实现字典设置
        pass
    
    def __delitem__(self, key):
        """字典删除"""
        # TODO: 实现字典删除
        pass
    
    def __iter__(self):
        """迭代支持"""
        # TODO: 实现迭代支持
        pass
    
    def __len__(self) -> int:
        """长度获取"""
        # TODO: 实现长度获取
        pass
    
    def __getattr__(self, name: str) -> Any:
        """点号访问支持"""
        # TODO: 实现点号访问
        # 提示: 将属性访问转换为字典访问
        pass
    
    def __setattr__(self, name: str, value: Any) -> None:
        """点号设置支持"""
        # TODO: 实现点号设置
        pass
    
    def __str__(self) -> str:
        return f"SmartDict({self._data})"
    
    def __repr__(self) -> str:
        return f"SmartDict({self._data!r})"


def demonstrate_magic_methods():
    """
    演示各种魔术方法的使用
    """
    print("=== Python魔术方法演示 ===")
    
    # 演示SmartNumber
    print("\n1. SmartNumber演示:")
    try:
        num1 = SmartNumber(10)
        num2 = SmartNumber(5)
        
        print(f"num1 = {num1}")
        print(f"repr(num1) = {repr(num1)}")
        print(f"num1 + num2 = {num1 + num2}")
        print(f"num1 > num2 = {num1 > num2}")
        print(f"hash(num1) = {hash(num1)}")
        print(f"bool(SmartNumber(0)) = {bool(SmartNumber(0))}")
        print(f"格式化: {num1:.2f}")
    except Exception as e:
        print(f"SmartNumber演示出错: {e}")
    
    # 演示SmartList
    print("\n2. SmartList演示:")
    try:
        smart_list = SmartList([1, 2, 3, 4, 5])
        
        print(f"smart_list = {smart_list}")
        print(f"len(smart_list) = {len(smart_list)}")
        print(f"smart_list[1:3] = {smart_list[1:3]}")
        print(f"3 in smart_list = {3 in smart_list}")
        print(f"reversed: {list(reversed(smart_list))}")
    except Exception as e:
        print(f"SmartList演示出错: {e}")
    
    # 演示CallableClass
    print("\n3. CallableClass演示:")
    try:
        @CallableClass
        def greet(name):
            return f"Hello, {name}!"
        
        result1 = greet("Alice")
        result2 = greet("Bob")
        
        print(f"调用结果: {result1}, {result2}")
        print(f"调用次数: {greet.call_count}")
        print(f"调用历史: {greet.call_history}")
    except Exception as e:
        print(f"CallableClass演示出错: {e}")
    
    # 演示AttributeProxy
    print("\n4. AttributeProxy演示:")
    try:
        proxy = AttributeProxy({'name': 'Python', 'version': '3.9'})
        
        print(f"proxy.name = {proxy.name}")
        proxy.author = 'Guido'
        print(f"设置后 proxy.author = {proxy.author}")
        print(f"访问日志: {proxy.access_log}")
    except Exception as e:
        print(f"AttributeProxy演示出错: {e}")
    
    # 演示ContextManager
    print("\n5. ContextManager演示:")
    try:
        with ContextManager("database") as cm:
            print(f"在上下文中: {cm}")
        print("上下文已退出")
    except Exception as e:
        print(f"ContextManager演示出错: {e}")
    
    # 演示SmartDict
    print("\n6. SmartDict演示:")
    try:
        smart_dict = SmartDict({'name': 'Python', 'type': 'language'})
        
        print(f"smart_dict['name'] = {smart_dict['name']}")
        print(f"smart_dict.type = {smart_dict.type}")
        smart_dict.version = '3.9'
        print(f"设置后: {smart_dict}")
        print(f"keys: {list(smart_dict.keys())}")
    except Exception as e:
        print(f"SmartDict演示出错: {e}")


if __name__ == "__main__":
    demonstrate_magic_methods()
